package com.motu.monstercity.server.game.verticle;

import com.motu.monstercity.module.common.servermanager.ServerManager;
import com.motu.monstercity.module.common.utility.ServerParam;
import com.motu.monstercity.module.common.verticle.GmVerticle;
import com.motu.monstercity.protocol.Common;
import com.motu.monstercity.server.game.logic.*;
import com.motu.monstercity.server.game.logichandler.SystemHandler;
import com.motu.monstercity.server.game.timedtask.TimedTaskManager;
import com.motu.monstercity.server.game.userdata.UserInfo;
import com.motu.monstercity.server.game.web.ServerOpenManager;
import com.motu.monstercity.server.game.web.WebVerticle;
import com.motu.vertx.module.utility.base.ServerConfig;
import com.motu.vertx.module.utility.main.MainService;
import com.motu.vertx.module.utility.toolset.PreLoaderUtils;
import com.motu.vertx.module.utility.toolset.Tool;
import com.motu.vertx.module.utility.vertx.VerticleTool;
import io.vertx.core.*;
import io.vertx.core.json.JsonObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;
import java.util.List;

public class MainVerticle extends AbstractVerticle {

	public static final Logger logger = LoggerFactory.getLogger(MainVerticle.class);

	@Override
	public void start(Promise<Void> startPromise) throws Exception {

		// 需要在这里获取配置，在startVerticle中通过config()获取不到
		JsonObject config = config();
		// 启动入口方法
		AbstractVerticle startVerticle = new AbstractVerticle() {
			@Override
			public void start() {
				logger.info("Game MainVerticle start");

				try {
					// 初始化公共服务
					MainService.init(vertx, config);

					// 初始化游戏基础配置数据
					Future.await(initBaseData());

					// 部署游戏业务Verticle
					Future.await(deployVerticles());

					// 预加载类
					preLoadClasses();

					logger.info("Game MainVerticle start success!!!");
					startPromise.complete();

				} catch (Throwable t) {
					/** 虚拟线程返回错误需要用Throwable才可以捕捉到异常 **/
					logger.error("Game MainVerticle start error cause:{}", Tool.getException(t));
					startPromise.fail(t);
				}

			}
		};

		// Run the verticle a on virtual thread
		vertx.deployVerticle(startVerticle, new DeploymentOptions().setThreadingModel(ThreadingModel.VIRTUAL_THREAD))
				.onComplete(res -> {
					if (res.succeeded()) {
						logger.info("Game startVerticle Deployment success id is: " + res.result());

						// 部署GmVerticle gm都要部署,用来重载,检测集群等（这个要最后部署，这样启动失败就无法检测集群）
						VerticleTool.deployVerticleIfNeeded(vertx, GmVerticle.class.getName(), VerticleTool.getDeploymentOptions("gm-verticle-instances", 1, ThreadingModel.VIRTUAL_THREAD));
					} else {
						logger.info("Game startVerticle Deployment failed:" + res.cause());
					}
				});

	}

	/**
	 * 初始化游戏基础配置数据
	 */
	public Future<Void> initBaseData() {
		Promise<Void> promise = Promise.promise();
		List<Future> futureList = new ArrayList<>();
		ServerManager.init(futureList);// 初始化服务器信息
		GameDataManager.init(futureList);// 公共数据初始化
		IapManager.init(futureList);// 付费商城数据初始化
		ActManager.initBaseData(futureList); // 活动初始化
		BagManager.init(futureList);// 背包模块
		PartnerManager.init(futureList);// 伙伴干员模块
		SkillManager.init(futureList);// 技能模块
		SuitManager.init(futureList);// 服装模块
		BuildManager.init(futureList);// 建筑模块
		SecretaryManager.init(futureList); // 秘书模块
		FightManager.init(futureList);// 战斗副本模块
		FeastManager.init(futureList);// 幸存者派对模块
		DatingManager.init(futureList);// 约会模块
		ChildManager.init(futureList);// 子嗣模块
		PatrolManager.initBaseData(futureList);// 巡查模块
		ShopManager.init(futureList);// 商店模块
		DrawManager.init(futureList);// 抽奖模块
		RankManager.init(futureList);// 榜单模块
		FloristManager.initData(futureList); // 花店模块
		ActDaysManager.initBaseData(futureList); // 七天乐模块
		MainTaskManager.init(futureList);// 主线任务模块
		EventManager.initBaseData(futureList); // 随机事件模块
		CaveManager.init(futureList);// 怪兽洞窟模块
		RestaurantManager.init(futureList);// 中餐厅模块
		RankActManager.initBaseData(futureList); // 冲榜活动模块
		UnionManager.init(futureList);// 联盟模块
		ActConventionManager.initBaseData(futureList); // 万能活动模块
		WorldManager.init(futureList);// 大世界行军模块
		UnionScuffleManager.initBaseData(futureList); // 联盟成就
		WorldBossBaseData.init(futureList); // 世界Boss
		UnionMobileManager.initBaseData(futureList); // 联盟总动员

		CompositeFuture.all(futureList).onComplete(handler->{
			if (handler.succeeded()) {
				promise.complete();
			} else {
				promise.fail(handler.cause());
			}
		});
		return promise.future();
	}

	/**
	 * 部署游戏业务Verticle
	 */
	public Future deployVerticles() {
		Promise promise = Promise.promise();
		List<Future<?>> list = new ArrayList<>();

		if (ServerConfig.isGameServer()) {

			// 部署游戏服
			deployGame(list);

		} else if (ServerConfig.isTimedTaskServer()) {

			// 部署定时服
			deployTimedTask(list);

			// 定时任务初始化（定时服部署好Verticle之后，才可以进行定时任务初始化，防止初始化时要分发任务到worker线程，而worker线程还没部署好）
			TimedTaskManager.init();

		} else if (ServerConfig.isWebServer()) {// web服进程
			list.add(VerticleTool.deployVerticleIfNeeded(vertx, WebVerticle.class.getName(), VerticleTool.getDeploymentOptions("web-verticle-instances", 1, ThreadingModel.VIRTUAL_THREAD)));
			ServerOpenManager.init(vertx);// 开启自动开服
		}

		Future.all(list).onComplete(promise);
		return promise.future();
	}

	/**
	 * 部署游戏服
	 */
	public void deployGame(List<Future<?>> list) {
		if (ServerConfig.isOnlineServer() && ServerConfig.isGameInit()) {// 正式服才需要部署game-init进程
			list.add(VerticleTool.deployVerticleIfNeeded(vertx, GameInitVerticle.class.getName(), VerticleTool.getDeploymentOptions("gameinit-verticle-instances", 8, ThreadingModel.VIRTUAL_THREAD)));
		} else {
			// 非正式服只需要部署game进程就可以了, game进程包含GameVerticle 和 GameInitVerticle
			if (!ServerConfig.isOnlineServer()) {
				list.add(VerticleTool.deployVerticleIfNeeded(vertx, GameInitVerticle.class.getName(), VerticleTool.getDeploymentOptions("gameinit-verticle-instances", 8, ThreadingModel.VIRTUAL_THREAD)));
			}
			list.add(VerticleTool.deployVerticleIfNeeded(vertx, GameVerticle.class.getName(), VerticleTool.getDeploymentOptions("game-verticle-instances", 8, ThreadingModel.VIRTUAL_THREAD)));
			list.add(VerticleTool.deployVerticleIfNeeded(vertx, GameCustomVerticle.class.getName(), VerticleTool.getDeploymentOptions("gamecustom-verticle-instances", 1, ThreadingModel.VIRTUAL_THREAD)));
			list.add(VerticleTool.deployVerticleIfNeeded(vertx, IapVerticle.class.getName(), VerticleTool.getDeploymentOptions("iap-verticle-instances", 1, ThreadingModel.VIRTUAL_THREAD)));
		}
		// 本地注册web进程，方便调试
		if (ServerConfig.isLocalServer()) {
			list.add(VerticleTool.deployVerticleIfNeeded(vertx, WebVerticle.class.getName(), VerticleTool.getDeploymentOptions("web-verticle-instances", 1, ThreadingModel.VIRTUAL_THREAD)));
		}
	}

	/**
	 * 部署定时服
	 */
	public void deployTimedTask(List<Future<?>> list) {
		if (ServerConfig.isTimedTaskWorker()) {

			/**
			 * 定时任务worker进程，可以部署多个，用于定时任务比较多的情况
			 * 注意：如果有worker进程，则先启动worker进程，再启动定时任务主进程，防止定时任务主进程启动时分发任务到worker进程时，worker进程正在启动中，可能导致任务丢失
			 */
			list.add(VerticleTool.deployVerticleIfNeeded(vertx, WorkVerticle.class.getName(), VerticleTool.getDeploymentOptions("work-verticle-instances", 4, ThreadingModel.VIRTUAL_THREAD)));

		} else {

			/**
			 * 定时任务主进程，只能部署一个（主进程也包含worker线程）
			 */
			list.add(VerticleTool.deployVerticleIfNeeded(vertx, TimeTaskVerticle.class.getName(), VerticleTool.getDeploymentOptions("timetask-verticle-instances", 1, ThreadingModel.VIRTUAL_THREAD)));
			list.add(VerticleTool.deployVerticleIfNeeded(vertx, WorkVerticle.class.getName(), VerticleTool.getDeploymentOptions("work-verticle-instances", 4, ThreadingModel.VIRTUAL_THREAD)));

			// 第三方充值
			JsonObject appConfig = ServerConfig.getAppConfig();
			if (appConfig.containsKey("game-iap-kafka-address")){
				JsonObject iapConfig = new JsonObject().put("iap-kafka-address", appConfig.getString("game-iap-kafka-address"));
				list.add(VerticleTool.deployVerticleIfNeeded(vertx, IapKafkaVerticle.class.getName(), VerticleTool.getDeploymentOptions(iapConfig, "iap-verticle-instances", 1, ThreadingModel.VIRTUAL_THREAD)));
			}
			// sdk充值
			if (appConfig.containsKey("iap-kafka-address")){
				JsonObject iapConfig = new JsonObject().put("iap-kafka-address", appConfig.getString("iap-kafka-address"));
				list.add(VerticleTool.deployVerticleIfNeeded(vertx, IapKafkaVerticle.class.getName(), VerticleTool.getDeploymentOptions(iapConfig, "iap-verticle-instances", 1, ThreadingModel.VIRTUAL_THREAD)));
			}

			if (!ServerConfig.isLocalServer()) {//通知网关服更新在线数
				list.add(VerticleTool.deployVerticleIfNeeded(vertx, MonitorVerticle.class.getName(), VerticleTool.getDeploymentOptions("saveonline-verticle-instances", 1, ThreadingModel.VIRTUAL_THREAD)));
			}

		}
	}

	/**
	 * 预加载一些类（异步的），提升后续访问速度
	 */
	private void preLoadClasses() {
		if (ServerParam.CLASS_PRELOAD_OPEN == 1) {
			logger.info("preLoadClasses enable");
		} else {
			logger.info("preLoadClasses disable");
			return;
		}
		// 建议传入项目都通用的类，例如SystemHandler
		// 配置类一般启动的时候会初始化，不需要预加载
		if (ServerConfig.isGameServer()) {
			PreLoaderUtils.preLoadClassWithDepth(vertx, true,
					SystemHandler.class.getPackage().getName(), 1, null);
			PreLoaderUtils.preLoadClassWithDepth(vertx, true,
					Common.class.getPackage().getName(), 0, null);
			PreLoaderUtils.preLoadClassWithDepth(vertx, true,
					GameDataManager.class.getPackage().getName(), 1, null);
			PreLoaderUtils.preLoadClassWithDepth(vertx, true,
					UserInfo.class.getPackage().getName(), 1, null);
		}
	}

}
